home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / nn.zip / MACRO.C < prev    next >
C/C++ Source or Header  |  1989-12-31  |  13KB  |  741 lines

  1. #include "config.h"
  2. #include "keymap.h"
  3. #include "term.h"
  4.  
  5. export int in_menu_mode = 0;
  6. export int get_from_macro = 0;
  7. export int macro_debug = 0;
  8. export char *dflt_enter_macro = NULL;
  9.  
  10. #define M_DUMMY        0    /* do nothing (end of branch)     */
  11.  
  12. #define    M_COMMAND    1    /* a command (get_c())          */
  13. #define M_KEY        2    /* a key stroke (get_c())      */
  14. #define M_STRING    3    /* a string (get_s())         */
  15.  
  16. #define M_INPUT        4    /* take input from keyboard (get_c/get_s) */
  17.  
  18. #define M_YES        5    /* answer yes to confirmation     */
  19. #define M_NO        6    /* answer no to confirmation and break */
  20.                 /* -- if neither are present, take input */
  21.  
  22. #define M_PUTS        7    /* puts "..."             */
  23. #define M_PROMPT    8    /* prompt(...)              */
  24. #define M_ECHO        9    /* msg(...)             */
  25.  
  26. #define M_IS_MENU    10    /* in menu mode ?         */
  27. #define M_IS_SHOW    11    /* in reading mode ?         */
  28. #define M_IS_GROUP    12    /* are we in a news group ?     */
  29. #define M_IS_FOLDER    13    /* are we in a folder ?         */
  30. #define M_CONFIRM    14    /* ask for confirmation to procede     */
  31. #define M_REJECT    15    /* ask for !confirmation to procede     */
  32. #define M_VARTEST    16    /* test value of variable     */
  33. #define M_BREAK        17    /* exit from macroes         */
  34. #define    M_RETURN    18    /* return from this macro     */
  35.  
  36. #define    M_SET_COMMAND    19    /* set/unset command         */
  37.  
  38.  
  39. struct macro {
  40.     int            m_type;        /* entry type */
  41.     union {
  42.     int         mu_int;        /* command or char */
  43.     char         *mu_string;    /* string for get_s */
  44.     struct macro     *mu_branch;    /* false conditional */
  45.     } m_value;
  46.     struct macro *m_next;        /* next macro element */
  47. };
  48.  
  49. #define m_int        m_value.mu_int
  50. #define m_string    m_value.mu_string
  51. #define m_branch    m_value.mu_branch
  52.  
  53. #define NMACRO 101        /* max number of macros */
  54. #define MSTACK 5        /* max nesting level */
  55.  
  56. static struct macro *macro[NMACRO + 1];     /* macro table */
  57.  
  58. static struct macro *mstack[MSTACK];    /* macro stack */
  59. static int cstack[MSTACK + 1];
  60. static int m_level = 0;
  61.  
  62. static struct macro *m = NULL;        /* current macro */
  63. static int no_advance = 0;
  64. static int changed_prompt = 0;
  65.  
  66. static int cur_m;
  67.  
  68. #define MERROR ((struct macro *)1)
  69.  
  70. init_macro()
  71. {
  72.     int n;
  73.     
  74.     for (n = 0; n <= NMACRO; n++)
  75.     macro[n] = NULL;
  76. }
  77.  
  78. static m_new(t)
  79. int t;
  80. {
  81.     struct macro *m1;
  82.     
  83.     m1 = (struct macro *)calloc(1, sizeof(struct macro));
  84.     mem_check((char *)m1, sizeof(struct macro), "for macro");
  85.  
  86.     if (m == NULL)
  87.     m = macro[cur_m] = m1;
  88.     else {
  89.     m->m_next = m1;
  90.     m = m1;
  91.     }
  92.     m->m_type = t;
  93.     m->m_next = NULL;
  94. }
  95.  
  96.  
  97. /*
  98.  *    Define macro "id" reading from file f until "end"
  99.  *
  100.  *    Macro definition syntax:
  101.  *        define <id>
  102.  *           <body>
  103.  *        end
  104.  */
  105.  
  106. static int initial_set_commands;
  107.  
  108. char *m_define(id, f)
  109. char *id;
  110. FILE *f;
  111. {
  112.     char line[256], *lp, skip;
  113.  
  114.     if (id) {
  115.     cur_m = atoi(id);
  116.     if (cur_m < 0)
  117.         cur_m = NMACRO;
  118.     else if (cur_m >= NMACRO) {
  119.         m_error("macro number out of range\n", id);
  120.         return (char *)0;
  121.     }
  122.     } else {
  123.     for (cur_m = 0; cur_m < NMACRO; cur_m++)
  124.         if (macro[cur_m] == NULL) break;
  125.     if (cur_m == NMACRO) {
  126.         init_message("No unused macro numbers");
  127.         return (char *)0;
  128.     }
  129.     }
  130.     
  131.     if (f == NULL) {
  132.     clrdisp();
  133.     printf("DEFINE MACRO %d -- END WITH 'end'\n\n\r", cur_m);
  134.     unset_raw();
  135.     f = stdin;
  136.     }
  137.     
  138.     m = NULL;
  139.     skip = 0;
  140.     initial_set_commands = (cur_m == NMACRO);
  141.     
  142.     while (fgets(line, 256, f)) {
  143.     for (lp = line; *lp && isspace(*lp); lp++);
  144.     if (*lp == NUL) continue;
  145.     if (*lp == ')' || strncmp(lp, "end", 3) == 0) goto out;
  146.     if (!skip && parse_line(lp)) {
  147.         macro[cur_m] = NULL;
  148.         skip++;
  149.     }
  150.     }
  151.  
  152.     if (f != stdin)
  153.     m_error("end missing", (char *)NULL);
  154.  
  155.  out:
  156.     if (f == stdin) raw();
  157.     m = NULL;
  158.     return (char *)macro[cur_m];
  159. }
  160.  
  161. char *m_get_macro(id)
  162. char *id;
  163. {
  164.     if (id) {
  165.     cur_m = atoi(id);
  166.     if (cur_m < 0 || cur_m >= NMACRO) {
  167.         m_error("macro number out of range\n", id);
  168.         return (char *)0;
  169.     }
  170.     } 
  171.     return (char *)macro[cur_m];
  172. }
  173.  
  174. char *parse_enter_macro(f, c)
  175. FILE *f;
  176. register int c;
  177. {
  178.     register char *gp;
  179.     char other[FILENAME];
  180.     group_header *gh;
  181.     static char *last_defined = NULL;
  182.     
  183.     while (c != EOF && c != NL && (!isascii(c) || isspace(c))) c = getc(f);
  184.  
  185.     if (c == ')') return last_defined;
  186.     
  187.     if (c == EOF) return (char *)NULL;
  188.     
  189.     if (c == NL) return last_defined = m_define("-1", f);
  190.  
  191.     gp = other; 
  192.     do {
  193.     *gp++ = c;
  194.     c = getc(f);
  195.     } while (c != EOF && c != ')' && isascii(c) && !isspace(c));
  196.  
  197.     *gp = NUL;
  198.     if (gh = lookup(other)) return gh->enter_macro;
  199.     
  200.     return m_get_macro(other);
  201. }
  202.  
  203. static parse_line(lp)
  204. char *lp;
  205. {
  206.     char *word;
  207.     struct macro *m1, *branch = NULL;
  208.  
  209.     while (*lp) {
  210.     if (*lp == '#') break;
  211.     
  212.     if (*lp == ':') {
  213.         lp++;
  214.         if (initial_set_commands) {
  215.         if (strncmp(lp, "local",  5) == 0 ||
  216.             strncmp(lp, "set",    3) == 0 || 
  217.             strncmp(lp, "unset",  5) == 0) {
  218.             m_new(M_SET_COMMAND);
  219.             m->m_string = copy_str(lp);
  220.             break;
  221.         }
  222.         initial_set_commands = 0;
  223.         }
  224.         m_new(M_COMMAND);
  225.         m->m_int = GETC_COMMAND | K_EXTENDED_CMD;
  226.         m_new(M_STRING);
  227.         m->m_string = copy_str(lp);
  228.         break;
  229.     }
  230.     initial_set_commands = 0;
  231.  
  232.     if (*lp == '?') {
  233.         m_new(M_IS_MENU);
  234.         if (branch == NULL) {
  235.         m1 = m;
  236.         m_new(M_DUMMY);
  237.         branch = m;
  238.         m = m1;
  239.         }
  240.         m->m_branch = branch;
  241.     }
  242.  
  243.     word = lp;
  244.     if (*lp == '"')
  245.         do lp++;
  246.         while (*lp && *lp != '"');
  247.     else
  248.     if (*lp == '\'')
  249.         do lp++;
  250.         while (*lp && *lp != '\'');
  251.     else
  252.         while (*lp && !isspace(*lp)) lp++;
  253.     if (*lp) {
  254.         *lp++ = NUL;
  255.         while (*lp && isspace(*lp)) lp++;
  256.     }
  257.     if (parse_word(word)) return 1;
  258.     }
  259.  
  260.     if (branch) {
  261.     m->m_next = branch;
  262.     m = branch;
  263.     }
  264.     return 0;
  265. }
  266.  
  267. static parse_word(w)
  268. char *w;
  269. {
  270.     int cmd;
  271.     register struct macro *m1;
  272.     
  273.     if (m && m->m_type == M_COMMAND && m->m_int == (GETC_COMMAND | K_MACRO)) {
  274.     if (isdigit(*w)) {
  275.         m->m_int |= atoi(w);
  276.         goto ok;
  277.     }
  278.     m_error("macro number missing", (char *)NULL);
  279.     return 1;
  280.     }
  281.  
  282.     if (*w == '"') {
  283.     if (m == NULL || (m->m_type != M_PROMPT && m->m_type != M_ECHO && m->m_type != M_PUTS))
  284.         m_new(M_STRING);
  285.     m->m_string = copy_str(w + 1);
  286.     goto ok;
  287.     }
  288.  
  289.     if (*w == '\'') {
  290.     m_new(M_KEY);
  291.     m->m_int = parse_key(w + 1);
  292.     goto ok;
  293.     }
  294.  
  295.     if (*w == '?') {
  296.     if (strchr(w, '=')) {
  297.         m->m_type = M_VARTEST;
  298.         m1 = m;
  299.         m_new(M_DUMMY);
  300.         m->m_branch = m1->m_branch;
  301.         m1->m_string = copy_str(w + 1);
  302.         goto ok;
  303.     }
  304.     
  305.     switch (w[1]) {
  306.      case 'f': /* ?folder */
  307.         cmd = M_IS_FOLDER;
  308.         break;
  309.      case 'g': /* ?group */
  310.         cmd = M_IS_GROUP;
  311.         break;
  312.      case 'm': /* ?menu */
  313.         cmd = M_IS_MENU;
  314.         break;
  315.      case 'n': /* ?no */
  316.         cmd = M_REJECT;
  317.         break;
  318.      case 's': /* ?show */
  319.         cmd = M_IS_SHOW;
  320.         break;
  321.      case 'y': /* ?yes */
  322.         cmd = M_CONFIRM;
  323.         break;
  324.      default:
  325.         m_error("unknown conditional %s", w - 1);
  326.         return 1;
  327.     }
  328.     m->m_type = cmd;
  329.     goto ok;
  330.     }
  331.  
  332.     if ((cmd = lookup_command(w, (K_ONLY_MENU | K_ONLY_MORE))) != K_INVALID) {
  333.     m_new(M_COMMAND);
  334.     m->m_int = GETC_COMMAND | cmd;
  335.     goto ok;
  336.     }
  337.  
  338.     if (strcmp(w, "prompt") == 0) {
  339.     m_new(M_PROMPT);
  340.     m->m_string = "?";
  341.     goto ok;
  342.     }
  343.     if (strcmp(w, "echo") == 0) {
  344.     m_new(M_ECHO);
  345.     m->m_string = "ups";
  346.     goto ok;
  347.     }
  348.     if (strcmp(w, "puts") == 0) {
  349.     m_new(M_PUTS);
  350.     m->m_string = "";
  351.     goto ok;
  352.     }
  353.     if (strcmp(w, "input") == 0) {
  354.     m_new(M_INPUT);
  355.     goto ok;
  356.     }
  357.     if (strcmp(w, "yes") == 0) {
  358.     m_new(M_YES);
  359.     goto ok;
  360.     }
  361.     if (strcmp(w, "no") == 0) {
  362.     m_new(M_NO);
  363.     goto ok;
  364.     }
  365.     if (strcmp(w, "break") == 0) {
  366.     m_new(M_BREAK);
  367.     goto ok;
  368.     }
  369.     if (strcmp(w, "return") == 0) {
  370.     m_new(M_RETURN);
  371.     goto ok;
  372.     }
  373.  
  374.     m_error("Unknown word >>%s<<", w);
  375.     return 1;
  376.  
  377.  ok:
  378.     return 0;
  379. }
  380.  
  381. /*
  382.  *    Invoke macro # N
  383.  */
  384.  
  385. m_invoke(n)
  386. int n;
  387. {
  388.     if (n < 0) {
  389.     n = NMACRO;
  390.     if ((macro[n] = (struct macro *)(current_group->enter_macro)) == NULL)
  391.         if ((macro[n] = (struct macro *)dflt_enter_macro) == NULL)
  392.         return;
  393.     } else 
  394.     if (n >= NMACRO || macro[n] == NULL) {
  395.     msg("undefined macro %d", n);
  396.     return;
  397.     }
  398.  
  399.     if (m_level == 0)
  400.     no_advance = 0;
  401.     else {
  402.     if (m_level > MSTACK) {
  403.         msg("Macro stack overflow");
  404.         m_break();
  405.         return;
  406.     }
  407.     mstack[m_level] = m;
  408.     cstack[m_level] = cur_m;
  409.     }
  410.     m_level++;
  411.  
  412.     cur_m = n;
  413.     m = macro[cur_m];
  414.     while (m && m->m_type == M_SET_COMMAND) {
  415.     char buffer[128];
  416.     strcpy(buffer, m->m_string); 
  417.     if (macro_debug) { msg(":%s", buffer); user_delay(1); }
  418.     parse_command(buffer, 0, (FILE *)NULL);
  419.     m = m->m_next;
  420.     }
  421. }
  422.  
  423. m_startinput()
  424. {
  425.     no_advance = 1;
  426. }
  427.  
  428. m_endinput()
  429. {
  430.     if (no_advance) {
  431.     no_advance = 0;
  432.     if (m && m->m_type == M_INPUT)
  433.         m = m->m_next;
  434.     }
  435. }
  436.  
  437. m_advinput()
  438. {
  439.     if (m && m->m_type == M_INPUT)
  440.     m = m->m_next;
  441. }
  442.  
  443. static struct macro *m_call(who)
  444. int who;
  445. {
  446.     struct macro *m1;
  447.  
  448.     for (;;) {
  449.     while (m == NULL && m_level > 1) {
  450.         m_level--;
  451.         m = mstack[m_level];
  452.         cur_m = cstack[m_level];
  453.     }
  454.     if (m == NULL) {
  455.         if (macro_debug) msg("end");
  456.         m_break();
  457.         return NULL;
  458.     }
  459.     
  460.     if (macro_debug) 
  461.         macro_dbg();
  462.         
  463.     if (who == 3) {
  464.         if (m->m_type == M_YES || m->m_type == M_NO) goto out;
  465.         return NULL;
  466.     }
  467.  
  468.     switch (m->m_type) {
  469.      case M_COMMAND:
  470.         if (m->m_int == (GETC_COMMAND | K_REDRAW))
  471.         changed_prompt = 0;
  472.      case M_KEY:
  473.         if (who == 1) goto out;
  474.         goto err;
  475.  
  476.      case M_STRING:
  477.         if (who == 2) goto out;
  478.         goto err;
  479.  
  480.      case M_INPUT:
  481.         if (no_advance) return m;
  482.         goto out;
  483.  
  484.      case M_YES:
  485.      case M_NO:
  486.      case M_DUMMY:
  487.         break;
  488.  
  489.      case M_PUTS:
  490.         fputs(m->m_string, stdout); fl;
  491.         break;
  492.         
  493.      case M_PROMPT:
  494.         if (m->m_string[0] == NUL) {
  495.         changed_prompt = 0;
  496.         break;
  497.         }
  498.         if (!changed_prompt) prompt(P_SAVE);
  499.         changed_prompt = 1;
  500.         prompt("\1%s\1 ", m->m_string);
  501.         break;
  502.  
  503.      case M_ECHO:
  504.         msg(m->m_string);
  505.         restore_xy();
  506.         break;
  507.  
  508.      case M_IS_MENU:
  509.         if (!in_menu_mode) m = m->m_branch;
  510.         break;
  511.      case M_IS_SHOW:
  512.         if (in_menu_mode) m = m->m_branch;
  513.         break;
  514.      case M_IS_GROUP:
  515.         if (current_group->group_flag & G_FOLDER) m = m->m_branch;
  516.         break;
  517.      case M_IS_FOLDER:
  518.         if ((current_group->group_flag & G_FOLDER) == 0) m = m->m_branch;
  519.         break;
  520.      case M_CONFIRM:
  521.         if (yes(0) == 0) m = m->m_branch;
  522.         break;
  523.      case M_REJECT:
  524.         if (yes(0) == 1) m = m->m_branch;
  525.         break;
  526.  
  527.      case M_VARTEST:
  528.         m1 = m;
  529.         m = m->m_next;
  530.         
  531.         switch (test_variable(m1->m_string)) {
  532.          case 0:
  533.         m = m->m_branch;
  534.         break;
  535.          case -1:
  536.         goto err1;
  537.         }
  538.         break;
  539.         
  540.      case M_RETURN:
  541.         m = NULL;
  542.         continue;
  543.  
  544.      case M_BREAK:
  545.         goto term;
  546.     }
  547.  
  548.     if (m) m = m->m_next;
  549.     }
  550.  
  551.  out:
  552.     m1 = m;
  553.     m = m->m_next;
  554.     no_advance = 0;
  555.     return m1;
  556.  
  557.  err:
  558.     msg("Error in macro %d", cur_m);
  559.  err1:
  560.     user_delay(1);
  561.     m_break();
  562.     return MERROR;
  563.  
  564.  term:
  565.     m_break();
  566.     return NULL;
  567. }
  568.  
  569. m_break_entry()
  570. {
  571.     if (current_group->enter_macro || dflt_enter_macro)
  572.     m = NULL;
  573. }
  574.  
  575. m_break()
  576. {
  577.     if (changed_prompt) prompt(P_RESTORE);
  578.     changed_prompt = 0;
  579.     m = NULL;
  580.     m_level = 0;
  581. }
  582.  
  583. macro_dbg()
  584. {
  585.     extern char *command_name(), *key_name();
  586.     char *name;
  587.     
  588.     switch (m->m_type) {
  589.      case M_COMMAND:
  590.     msg("COMMAND: %s", command_name(m->m_int));
  591.     goto delay;
  592.     
  593.      case M_KEY:
  594.     msg("KEY: %s", key_name(m->m_int));
  595.     goto delay;
  596.     
  597.      case M_STRING:
  598.     msg("STRING: %s", m->m_string);
  599.     goto delay;
  600.     
  601.      case M_INPUT:
  602.     name = "input";
  603.     break;
  604.     
  605.      case M_YES:
  606.     name = "yes";
  607.     break;
  608.     
  609.      case M_NO:
  610.     name = "no";
  611.     break;
  612.     
  613.      case M_DUMMY:
  614.     name = "dummy";
  615.     break;
  616.     
  617.      case M_PROMPT:
  618.     msg("PROMPT: %s", m->m_string);
  619.     goto delay;
  620.     
  621.      case M_ECHO:
  622.     msg("ECHO: %s", m->m_string);
  623.     goto delay;
  624.     
  625.      case M_IS_MENU:
  626.     msg("?menu => %d", in_menu_mode);
  627.     goto delay;
  628.  
  629.      case M_IS_SHOW:
  630.     msg("?show => %d", !in_menu_mode);
  631.     goto delay;
  632.  
  633.      case M_IS_GROUP:
  634.     msg("?group => %d", (current_group->group_flag & G_FOLDER) == 0);
  635.     goto delay;
  636.  
  637.      case M_IS_FOLDER:
  638.     msg("?group => %d", (current_group->group_flag & G_FOLDER));
  639.     goto delay;
  640.  
  641.      case M_CONFIRM:
  642.     name = "?yes";
  643.     break;
  644.  
  645.      case M_REJECT:
  646.     name = "?no";
  647.     break;
  648.     
  649.      case M_VARTEST:
  650.     msg("?%s => %d", m->m_string, test_variable(m->m_string));
  651.     goto delay;
  652.     
  653.      case M_RETURN:
  654.     name = "return";
  655.     break;
  656.  
  657.      case M_BREAK:
  658.     name = "break";
  659.     break;
  660.     }
  661.     msg(name);
  662.  
  663.  delay:
  664.     user_delay(1);
  665. }    
  666. /*
  667.  *    Macro processing for get_c()
  668.  */
  669.  
  670. m_getc(cp)
  671. int *cp;
  672. {
  673.     struct macro *m1;
  674.     
  675.     get_from_macro = 0;
  676.     if (m_level && (m1 = m_call(1))) {
  677.     if (m1 == MERROR) return 2;
  678.     if (m1->m_type == M_INPUT) return 0;
  679.     *cp = m1->m_int;
  680.     get_from_macro = 1;
  681.     return 1;
  682.     }
  683.     return 0;
  684. }
  685.  
  686. /*
  687.  *    Macro processing for get_s()
  688.  */
  689.  
  690. m_gets(s)
  691. char *s;
  692. {
  693.     struct macro *m1;
  694.  
  695.     get_from_macro = 0;
  696.     if (m_level && (m1 = m_call(2))) {
  697.     if (m1 == MERROR) return 2;
  698.     if (m1->m_type == M_INPUT) return 0;
  699.     strcpy(s, m1->m_string);
  700.     get_from_macro = 1;
  701.     return 1;
  702.     }
  703.     return 0;
  704. }
  705.  
  706. /*
  707.  *    Macro processing for yes()
  708.  */
  709.  
  710. m_yes()
  711. {
  712.     struct macro *m1;
  713.  
  714.     if (m)
  715.     if (m->m_type == M_CONFIRM || m->m_type == M_REJECT) return 3;
  716.     
  717.     if (m_level) {
  718.     if (m1 = m_call(3))
  719.         if (m1->m_type == M_NO)
  720.         return 1;
  721.         else
  722.         return 2;
  723.     else
  724.         return 3;
  725.     }
  726.     return 0;
  727. }
  728.  
  729. static m_error(fmt, arg)
  730. char *fmt, *arg;
  731. {
  732.     char buf[80];
  733.  
  734.    if (arg) {
  735.        sprintf(buf, fmt, arg);
  736.        fmt = buf;
  737.    }
  738.  
  739.    init_message("Error in macro %d: %s", cur_m, fmt);
  740. }
  741.